//+------------------------------------------------------------------+
//|                                              SignalSystemNew.mqh |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024"
#property link      ""
#property version   "1.00"
#property strict

// Signal types enumeration
enum ENUM_SIGNAL_TYPE {
    SIGNAL_MA_CROSS,
    SIGNAL_RSI_OVERBOUGHT,
    SIGNAL_RSI_OVERSOLD,
    SIGNAL_MACD_CROSS,
    SIGNAL_BB_UPPER,
    SIGNAL_BB_LOWER,
    SIGNAL_CCI_OVERBOUGHT,
    SIGNAL_CCI_OVERSOLD,
    SIGNAL_KDJ_CROSS,
    SIGNAL_VOLUME
};

// Signal structure
struct Signal {
    ENUM_SIGNAL_TYPE type;
    double strength;      // Signal strength (-1 to 1)
    double weight;        // Signal weight in final decision
    datetime time;        // Signal time
    bool isActive;        // Is signal still active
};

// Signal system class
class CSignalSystem {
private:
    Signal m_signals[];
    int m_signalCount;
    
    // Indicator handles
    int m_maHandle;
    int m_rsiHandle;
    int m_macdHandle;
    int m_bbHandle;
    int m_cciHandle;
    int m_kdjHandle;
    int m_volumeHandle;
    
    // Signal weights
    double m_signalWeights[10];  // Weights for each signal type
    
public:
    // Constructor
    CSignalSystem() {
        m_signalCount = 0;
        
        // Initialize default signal weights
        m_signalWeights[SIGNAL_MA_CROSS] = 0.2;
        m_signalWeights[SIGNAL_RSI_OVERBOUGHT] = 0.1;
        m_signalWeights[SIGNAL_RSI_OVERSOLD] = 0.1;
        m_signalWeights[SIGNAL_MACD_CROSS] = 0.2;
        m_signalWeights[SIGNAL_BB_UPPER] = 0.1;
        m_signalWeights[SIGNAL_BB_LOWER] = 0.1;
        m_signalWeights[SIGNAL_CCI_OVERBOUGHT] = 0.05;
        m_signalWeights[SIGNAL_CCI_OVERSOLD] = 0.05;
        m_signalWeights[SIGNAL_KDJ_CROSS] = 0.05;
        m_signalWeights[SIGNAL_VOLUME] = 0.05;
    }
    
    // Initialize indicators
    bool Initialize() {
        // Create MA indicator
        m_maHandle = iMA(Symbol(), PERIOD_CURRENT, 50, 0, MODE_SMA, PRICE_CLOSE);
        if(m_maHandle == INVALID_HANDLE) return false;
        
        // Create RSI indicator
        m_rsiHandle = iRSI(Symbol(), PERIOD_CURRENT, 14, PRICE_CLOSE);
        if(m_rsiHandle == INVALID_HANDLE) return false;
        
        // Create MACD indicator
        m_macdHandle = iMACD(Symbol(), PERIOD_CURRENT, 12, 26, 9, PRICE_CLOSE);
        if(m_macdHandle == INVALID_HANDLE) return false;
        
        // Create Bollinger Bands indicator
        m_bbHandle = iBands(Symbol(), PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
        if(m_bbHandle == INVALID_HANDLE) return false;
        
        // Create CCI indicator
        m_cciHandle = iCCI(Symbol(), PERIOD_CURRENT, 14, PRICE_CLOSE);
        if(m_cciHandle == INVALID_HANDLE) return false;
        
        // Create KDJ indicator
        m_kdjHandle = iStochastic(Symbol(), PERIOD_CURRENT, 5, 3, 3, MODE_SMA, STO_LOWHIGH);
        if(m_kdjHandle == INVALID_HANDLE) return false;
        
        return true;
    }
    
    // Deinitialize indicators
    void Deinitialize() {
        if(m_maHandle != INVALID_HANDLE) IndicatorRelease(m_maHandle);
        if(m_rsiHandle != INVALID_HANDLE) IndicatorRelease(m_rsiHandle);
        if(m_macdHandle != INVALID_HANDLE) IndicatorRelease(m_macdHandle);
        if(m_bbHandle != INVALID_HANDLE) IndicatorRelease(m_bbHandle);
        if(m_cciHandle != INVALID_HANDLE) IndicatorRelease(m_cciHandle);
        if(m_kdjHandle != INVALID_HANDLE) IndicatorRelease(m_kdjHandle);
    }
    
    // Check for MA cross signal
    bool CheckMACross() {
        double maBuffer[];
        ArraySetAsSeries(maBuffer, true);
        
        if(CopyBuffer(m_maHandle, 0, 0, 3, maBuffer) != 3) return false;
        
        // Check for bullish cross
        if(maBuffer[1] < maBuffer[2] && maBuffer[0] > maBuffer[1]) {
            AddSignal(SIGNAL_MA_CROSS, 1.0);
            return true;
        }
        
        // Check for bearish cross
        if(maBuffer[1] > maBuffer[2] && maBuffer[0] < maBuffer[1]) {
            AddSignal(SIGNAL_MA_CROSS, -1.0);
            return true;
        }
        
        return false;
    }
    
    // Check for RSI signals
    bool CheckRSISignals() {
        double rsiBuffer[];
        ArraySetAsSeries(rsiBuffer, true);
        
        if(CopyBuffer(m_rsiHandle, 0, 0, 1, rsiBuffer) != 1) return false;
        
        // Check for overbought
        if(rsiBuffer[0] > 70) {
            AddSignal(SIGNAL_RSI_OVERBOUGHT, -1.0);
            return true;
        }
        
        // Check for oversold
        if(rsiBuffer[0] < 30) {
            AddSignal(SIGNAL_RSI_OVERSOLD, 1.0);
            return true;
        }
        
        return false;
    }
    
    // Check for MACD signals
    bool CheckMACDSignals() {
        double macdMainBuffer[];
        double macdSignalBuffer[];
        ArraySetAsSeries(macdMainBuffer, true);
        ArraySetAsSeries(macdSignalBuffer, true);
        
        if(CopyBuffer(m_macdHandle, 0, 0, 3, macdMainBuffer) != 3) return false;
        if(CopyBuffer(m_macdHandle, 1, 0, 3, macdSignalBuffer) != 3) return false;
        
        // Check for bullish cross
        if(macdMainBuffer[1] < macdSignalBuffer[1] && macdMainBuffer[0] > macdSignalBuffer[0]) {
            AddSignal(SIGNAL_MACD_CROSS, 1.0);
            return true;
        }
        
        // Check for bearish cross
        if(macdMainBuffer[1] > macdSignalBuffer[1] && macdMainBuffer[0] < macdSignalBuffer[0]) {
            AddSignal(SIGNAL_MACD_CROSS, -1.0);
            return true;
        }
        
        return false;
    }
    
    // Check for Bollinger Bands signals
    bool CheckBBSignals() {
        double bbUpperBuffer[];
        double bbLowerBuffer[];
        double bbMiddleBuffer[];
        ArraySetAsSeries(bbUpperBuffer, true);
        ArraySetAsSeries(bbLowerBuffer, true);
        ArraySetAsSeries(bbMiddleBuffer, true);
        
        if(CopyBuffer(m_bbHandle, 1, 0, 1, bbUpperBuffer) != 1) return false;
        if(CopyBuffer(m_bbHandle, 2, 0, 1, bbLowerBuffer) != 1) return false;
        if(CopyBuffer(m_bbHandle, 0, 0, 1, bbMiddleBuffer) != 1) return false;
        
        double currentPrice = SymbolInfoDouble(Symbol(), SYMBOL_BID);
        
        // Check for upper band touch
        if(currentPrice >= bbUpperBuffer[0]) {
            AddSignal(SIGNAL_BB_UPPER, -1.0);
            return true;
        }
        
        // Check for lower band touch
        if(currentPrice <= bbLowerBuffer[0]) {
            AddSignal(SIGNAL_BB_LOWER, 1.0);
            return true;
        }
        
        return false;
    }
    
    // Check for CCI signals
    bool CheckCCISignals() {
        double cciBuffer[];
        ArraySetAsSeries(cciBuffer, true);
        
        if(CopyBuffer(m_cciHandle, 0, 0, 1, cciBuffer) != 1) return false;
        
        // Check for overbought
        if(cciBuffer[0] > 100) {
            AddSignal(SIGNAL_CCI_OVERBOUGHT, -1.0);
            return true;
        }
        
        // Check for oversold
        if(cciBuffer[0] < -100) {
            AddSignal(SIGNAL_CCI_OVERSOLD, 1.0);
            return true;
        }
        
        return false;
    }
    
    // Check for KDJ signals
    bool CheckKDJSignals() {
        double kBuffer[];
        double dBuffer[];
        ArraySetAsSeries(kBuffer, true);
        ArraySetAsSeries(dBuffer, true);
        
        if(CopyBuffer(m_kdjHandle, 0, 0, 3, kBuffer) != 3) return false;
        if(CopyBuffer(m_kdjHandle, 1, 0, 3, dBuffer) != 3) return false;
        
        // Check for bullish cross
        if(kBuffer[1] < dBuffer[1] && kBuffer[0] > dBuffer[0]) {
            AddSignal(SIGNAL_KDJ_CROSS, 1.0);
            return true;
        }
        
        // Check for bearish cross
        if(kBuffer[1] > dBuffer[1] && kBuffer[0] < dBuffer[0]) {
            AddSignal(SIGNAL_KDJ_CROSS, -1.0);
            return true;
        }
        
        return false;
    }
    
    // Check for volume signals
    bool CheckVolumeSignals() {
        double volumeBuffer[];
        ArraySetAsSeries(volumeBuffer, true);
        
        if(CopyBuffer(m_volumeHandle, 0, 0, 20, volumeBuffer) != 20) return false;
        
        // Calculate average volume
        double avgVolume = 0;
        for(int idx = 1; idx < 20; idx++) {
            avgVolume += volumeBuffer[idx];
        }
        avgVolume /= 19;
        
        // Check for volume spike
        if(volumeBuffer[0] > avgVolume * 2) {
            AddSignal(SIGNAL_VOLUME, 1.0);
            return true;
        }
        
        return false;
    }
    
    // Add new signal
    void AddSignal(ENUM_SIGNAL_TYPE type, double strength) {
        Signal signal;
        signal.type = type;
        signal.strength = strength;
        signal.weight = m_signalWeights[type];
        signal.time = TimeCurrent();
        signal.isActive = true;
        
        ArrayResize(m_signals, m_signalCount + 1);
        m_signals[m_signalCount++] = signal;
    }
    
    // Calculate final signal
    double CalculateFinalSignal() {
        double finalSignal = 0;
        double totalWeight = 0;
        
        // Remove old signals (older than 1 hour)
        datetime currentTime = TimeCurrent();
        for(int idx = m_signalCount - 1; idx >= 0; idx--) {
            if(currentTime - m_signals[idx].time > 3600) {
                // Remove old signal
                for(int jdx = idx; jdx < m_signalCount - 1; jdx++) {
                    m_signals[jdx] = m_signals[jdx + 1];
                }
                m_signalCount--;
            }
        }
        
        // Calculate weighted signal
        for(int idx = 0; idx < m_signalCount; idx++) {
            if(m_signals[idx].isActive) {
                finalSignal += m_signals[idx].strength * m_signals[idx].weight;
                totalWeight += m_signals[idx].weight;
            }
        }
        
        if(totalWeight > 0) {
            finalSignal /= totalWeight;
        }
        
        return finalSignal;
    }
    
    // Get signal count
    int GetSignalCount() {
        return m_signalCount;
    }
    
    // Get signal at index
    bool GetSignal(int index, Signal &signal) {
        if(index < 0 || index >= m_signalCount) return false;
        
        signal = m_signals[index];
        return true;
    }
    
    // Set signal weight
    void SetSignalWeight(ENUM_SIGNAL_TYPE type, double weight) {
        if(type >= 0 && type < 10) {
            m_signalWeights[type] = weight;
        }
    }
}; 